#include "RpcProvider.h"
#include <csignal>
#include <cstddef>
#include <cstdint>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <string>
#include <sys/types.h>
#include "MrpcApplication.h"
#include <muduo/net/TcpServer.h>
#include <muduo/net/InetAddress.h>
// #include <muduo/net/TcpConnection.h>
#include <muduo/net/Buffer.h>
#include <muduo/base/Timestamp.h>
#include <unordered_map>
#include "include/RpcProvider.h"
#include "rpc_header.pb.h"// 这里是框架提供的头文件
#include "zookeeperutil.h"
#include <zookeeper/zookeeper.h>

void RpcProvider::NotifyService(google::protobuf::Service * service){
    //start: // 这里是框架提供的外部进行注册
    ServiceInfo sinfo;
    // 这里是框架提供的外部进行注册，const google::protobuf::ServiceDescriptor*框架会自动提供的类型
    const google::protobuf::ServiceDescriptor* service_ptr = service->GetDescriptor();
    // 获取服务名
    const std::string service_name = service_ptr->name();
    int n = service_ptr -> method_count();
    // 遍历所有方法：
    for(int i=0; i<n; i++){
        const google::protobuf::MethodDescriptor* method_ptr = service_ptr->method(i);//获取方法描述符
        const std::string method_name = method_ptr->name(); //获取方法名
        sinfo._method_dic.insert({method_name, method_ptr});
    }
    // 服务对象
    sinfo._service_ptr = service; //
    this->_service_dic.insert({service_name, sinfo});//多用this指针，比较清晰。
}

void RpcProvider::Run(){
    //下面这句代码，就是启动muduo的网络服务
    std::string ip = MrpcApplication::GetInstance().GetConfig().Load("rpcserverip");//拿到配置文件的ip和port
    uint16_t port = std::stoi(MrpcApplication::GetInstance().GetConfig().Load("rpcserverport"));
    
    /*muduo 库的使用：网络编程，多线程，异步io，多线程的创建过程 start*/
    //muduo 创建InetAddress对象,网络地址对象
    muduo::net::InetAddress address(ip,port);
    
    //创建tcpserver对象
    muduo::net::TcpServer server(&this->_eventLoop,address,"RpcProvider");
    //设置连接回调
    server.setConnectionCallback(std::bind(&RpcProvider::OnConnection,this,std::placeholders::_1));
    //设置消息回调
    server.setMessageCallback(std::bind(&RpcProvider::OnMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));
    //设置线程数量
    server.setThreadNum(4);

    //创建zk对象，使用zookeeper客户端做服务对象，实现
    Zkclient zkclient_;
    zkclient_.Start();
    
    for(const auto &[str, service_info] :this -> _service_dic){
        std::string service = "/"+str; //服务名
        std::cout << "service:" << service << std::endl;
        zkclient_.Create(service,"", 0); //创建znode节点，持久节点，持久节点才能有子节点
        for(const auto &[method_name, method_ptr] : service_info._method_dic){
            std::string method = service + "/" + method_name;
            std::string znodo_data = ip + ":" + std::to_string(port);
            zkclient_.Create( method, znodo_data,ZOO_EPHEMERAL); //创建znode节点，临时节点
        }
    }

    //启动网络服务
    server.start();
    //处理网络I/O事件
    std::cout<<"RpcProvider start service at ip:"<<ip<<" port:"<<port<<std::endl;
    _eventLoop.loop();
    /* muduo 库的基础使用 end*/
}

//新的socket链接回调
void RpcProvider::OnConnection(const muduo::net::TcpConnectionPtr &conn){
//客户端主动关闭了连接；
// 网络异常导致连接中断；
// 服务端主动关闭了连接。
    if(!conn->connected()){
        //连接断开
        conn->shutdown();
    }
}

//框架内部调用的消息处理函数,需要实现序列化和反序列化也是使用google::protobuf,其中前
void RpcProvider::OnMessage(const muduo::net::TcpConnectionPtr &conn,
                            muduo::net::Buffer *buffer,
                            muduo::Timestamp time){//填入OnMessage
    std::string buffer_str = buffer->retrieveAllAsString();
    uint32_t len = 0;
    buffer_str.copy((char *)&len, 4,0); //获取消息长度，防止TCP流的粘包，前4字节为消息头长度，防止粘包，双方约定好，
    //解析 rpc_header对象
    std::string rpc_header_str = buffer_str.substr(4,len);
    mrpc::RpcHeader rpcheader = mrpc::RpcHeader();//
    if(!rpcheader.ParseFromString(rpc_header_str)){
        std::cout<<"rpcheader解析失败"<<std::endl;
        return ;
    }
    std::string service_name = rpcheader.service_name();
    std::string method_name = rpcheader.method_name();
    uint32_t args_len = rpcheader.args_len();
    //找到相应的service_method
    if(!this->_service_dic.count(service_name)){
        std::cout<<"没有找到服务"<<std::endl;
        return;
    }
    ServiceInfo service_info = this->_service_dic[service_name];
    google::protobuf::Service * service = service_info._service_ptr;//获取服务对象的指针。new UserService()
    if(!service_info._method_dic.count(method_name)){
        std::cout<<"没有找到方法"<<std::endl;
        return;
    }
    const google::protobuf::MethodDescriptor* method_des = service_info._method_dic[method_name];//获取方法对象的指针 Login
    std::string args_str = buffer_str.substr(4+len, args_len);
    //解析args。
    google::protobuf::Message *request = service->GetRequestPrototype(method_des).New(); //得到方法的请求参数，
    google::protobuf::Message *response = service->GetResponsePrototype(method_des).New(); //得到方法的返回参数
    if(!request->ParseFromString(args_str)){
        std::cout<<"request解析失败"<<std::endl;
        return ;
    }
    std::cout<<"解析成功:---------"<<std::endl;
    std::cout<<"service_name:"<<service_name<<std::endl;
    std::cout<<"method_name:"<<method_name<<std::endl;
    std::cout<<"args:"<<args_str<<std::endl;
    std::cout<<"打印结果:---------"<<std::endl;

    //给下面的method方法的调用，绑定一个Closure的回调函数,回调对象
    // // See Closure.
    // template <typename Class, typename Arg1, typename Arg2>
    // inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2),
    //                             Arg1 arg1, Arg2 arg2) {
    //   return new internal::MethodClosure2<Class, Arg1, Arg2>(
    //     object, method, true, arg1, arg2);
    // }
    //NewCallback 创建闭包的方法，有多种，可以使类中的函数（方法），也可是是静态函数
    auto done = google::protobuf::NewCallback<RpcProvider, const muduo::net::TcpConnectionPtr&, google::protobuf::Message*>(
        this, &RpcProvider::SendRpcResponse, conn, response);  // 创建Closure 对象（闭包）,绑定RPC请求的回调操作，done.run() = RpcProvider::SendRpcResponse(conn, response)
        // 对应于执行回调操作 执行响应对象数据的序列化和网络发送（都是由框架来完成的)。done.run();

    //在框架上根据远端rpc请求，调用当前rpc节点上发布的方法
    // new UserService().Login(controller, request, responser, done);
    // service->CallMethod(method_des, nullptr, request, response, done);//使用基类指针进行操作，使用抽象的方法
    // 调用抽象方法，即Login方法。
    service->CallMethod(method_des,nullptr,request,response,done);//方法，绑定request，和response以及Closure
}
//done.run();Closure绑定的SendRpcResponse函数
void RpcProvider::SendRpcResponse(const muduo::net::TcpConnectionPtr  &conn, google::protobuf::Message* response){ //
    std::string response_str;
    if(response->SerializePartialToString(&response_str)){ // response进行序列化。
        conn->send(response_str); //序列化成功，发送给客户端
    }
    else{
        std::cout<<"serialize response_str error"<<std::endl;
    }
    conn->shutdown();//模拟http的短连接服务，由rpcprovider主动断开连接。
}

